package com.mad.game.view.models;

import java.awt.Point;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.mad.game.backend.GameDemo;
import com.mad.game.system.Vector2;
import com.mad.game.view.ViewManager;

public class ModelPool {

	public static final String  GROUND = "ground",
								GROUND1 = "ground0",
								GROUND2 = "ground1",
								GROUND3 = "ground2",
								PLAYER = "player";
	
	private static final int extractValueFromGroundTileID(String tileID){
		return Integer.parseInt(tileID.substring(GROUND.length(), tileID.length()));
	}
	
	public static String getNextGroundTileID(String currentTileID){		
		int val = (extractValueFromGroundTileID(currentTileID)+1) % 3 ; 
		return GROUND.concat(String.valueOf(val)); 
	}
	public static String getPreviousGroundTileID(String currentTileID){		
		int val = (extractValueFromGroundTileID(currentTileID)-1) % 3 ; 
		return GROUND.concat(String.valueOf(val)); 
	}
	
	public static final String generateModelID(GameModel model){
		return String.valueOf(model.hashCode());
	}
	
	public static final boolean isBullet(GameModel model){
		return model instanceof ModelBullet ; 
	}

	public static final boolean isEntity(GameModel model) {
		return model instanceof ModelEntity ; 
	}
	
	public static final boolean isPlayer(GameModel model){
		return model instanceof ModelPlayer ; 
	}
	
	public static final boolean isEnemy(GameModel model){
		return model instanceof ModelEnemy ; 
	}
	
	public static final  boolean doesBulletCollideWithEntity(GameModel model1, GameModel model2){
		return (isBullet(model1) && isEntity(model2))
//		||
//				(isBullet(model2) && isEntity(model1)) 
		; 
	}
	
	public static final boolean doesPlayerCollideWithEnemy(GameModel model1, GameModel model2){
		return (isEnemy(model1) && isPlayer(model2))
//				|| 
//				isEnemy(model2) && isPlayer(model1))
				; 
	}
	
	private Map<String, GameModel> models ; 
	
	public Map<String, GameModel> getModels() {
		return models;
	}

	public ModelPool() {
		this.models = new HashMap<String, GameModel>(); 
		this.models.put(GROUND1, new ModelGround.ModelGround1()); 
		this.models.put(GROUND2, new ModelGround.ModelGround2()); 
		this.models.put(GROUND3, new ModelGround.ModelGround3()); 
	}

	public void addNewModel(String id, GameModel model){
		if(id != null && model != null)
			this.models.put(id, model);
	}

	@SuppressWarnings("unchecked")
	private HashMap<String, GameModel> cloneModels(){
		return (HashMap<String, GameModel>) ((HashMap<String, GameModel>)this.models).clone();
	}
	
	public void removeModel(String id){
		this.models.remove(id);
	}	
	public void removeModel(GameModel model){
		this.removeModel(String.valueOf(model.hashCode()));
	}

	public void spawnMob() {
		ModelEnemy enemy = new ModelEnemy();
		this.models.put(generateModelID(enemy), enemy);
		Vector2 camPos = GameDemo.getGameInstance().getCameraPosition().invert() ; 
		Point spawnPos = new Point(camPos.getX()+ViewManager.MAIN_WND_WIDTH, ViewManager.MAIN_WND_HEIGHT-50);
		enemy.setPosition(spawnPos);
		System.out.println(spawnPos);
		
	}
	
	public void spawnPlayer(){
		this.removeModel(PLAYER);
		this.models.put(PLAYER, new ModelPlayer()); 
	}
	
	public GameModel getModelById(String objectID){
		return this.models.get(objectID);
	}
	
	public void update(){
		for (GameModel g : this.cloneModels().values())
			g.update();
	}
	
	private void performBulletHitAction(GameModel model1, GameModel model2) {
		ModelEntity entity = (ModelEntity) (isBullet(model1) ? model2 : model1) ; 
		ModelBullet bullet = (ModelBullet) (isBullet(model1) ? model1 : model2) ;
		entity.changeHealth(-bullet.DAMAGE);
		System.out.println(bullet.DAMAGE);
		if(entity.isDead())
			this.removeModel(entity);
	}
	
	private void performPlayerMeetsEnemyAction(GameModel model1, GameModel model2){
		ModelPlayer player = (ModelPlayer) (isPlayer(model1) ? model1 : model2) ; 
//		player.die() ; 
//		if(player.isDead()){
//			this.removeModel(PLAYER);
//			System.out.println("You died!");
//			return ; 
//		}
	}
	
	int i = 0 ; 
	public GameModel doesModelCollide_inMovement(GameModel model){
		i++ ; 
		List<GameModel> toRemove = new ArrayList<GameModel>();
		GameModel toReturn = null ; 
		for(GameModel m: this.cloneModels().values()){
			if(model != null && m != null && model != m){
				if(!model.isFixed() && GameModel.doModelsCollide_inMovement(model, m)){
					toReturn = m;
					if(isPlayer(model) && !GameDemo.getGameInstance().canMoveCamera())
						GameDemo.getGameInstance().setCanMoveCamera(true); 
					if(isBullet(model)) 
						toRemove.add(model);
					if(doesBulletCollideWithEntity(model, m)){
//						System.out.println(
//								"Bullet: "+(isBullet(model)?"model":"m")+";"+" Entity: "+(isEntity(model)?"model":"m;"+
//										"\nIteration: "+i));
						this.performBulletHitAction(model, m);						
					}
					else if(doesPlayerCollideWithEnemy(model, m))
						this.performPlayerMeetsEnemyAction(model, m);
					for(GameModel m1: toRemove)
						this.removeModel(m1);
					return toReturn ; 
				}
			}
		}
		return null ; 
	}
	
	public GameModel doesModelCollide(GameModel model){
		for(GameModel m: this.cloneModels().values()){
			if(model != null && m != null && model != m){
				if(!model.isFixed() && GameModel.doModelsCollide_inMovement(model, m))
					return m;
			}
		}
		return null ; 
	}

	public void moveEntityLeft(String id){
		((ModelEntity)this.getModelById(id)).moveLeft();
	}
	public void moveEntityRight(String id){
		((ModelEntity)this.getModelById(id)).moveRight();
	}
	public void jumpEntityInMove(String id){
		((ModelEntity)this.getModelById(id)).jumpInMove();
	}
	public void jumpEntityStraightUp(String id){
		((ModelEntity)this.getModelById(id)).jumpStraightUp();
	}
	public boolean doesEntityJump(String id){
		return ((ModelEntity)this.getModelById(id)).isJumping();
	}
	public void entityShoot(String id){
		((ModelEntity)this.getModelById(id)).shoot();
	}
}
